package com.feidee.data.report.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.feidee.data.report.constant.Constant;
import com.feidee.data.report.exception.DataDaoException;
import com.feidee.data.report.exception.DataReporterServiceException;
import com.feidee.data.report.model.*;
import com.feidee.data.report.model.Dependency.DataMonitorModel;
import com.feidee.data.report.model.Dependency.DependencyModel;
import com.feidee.data.report.model.Dependency.DependencyResourcesModel;
import com.feidee.data.report.model.RealTimeReportConfigModel.RealTimeConfigModel;
import com.feidee.data.report.service.DataReporterService;
import com.feidee.data.report.service.IFunnelAnalyseServices;
import com.feidee.data.report.service.IRealTimeReportServices;
import com.feidee.data.report.util.JdbcManager;
import com.feidee.data.report.util.RunFlagController;
import com.feidee.data.report.util.ToolUtils;
import com.feidee.data.report.util.threadutil.ThreadPoolUtil;
import com.feidee.fdcommon.authorization.AuthorizationVerify;
import com.feidee.fdcommon.authorization.model.AuthorizationModel;
import com.feidee.fdcommon.configuration.CustomConfiguration;
import com.feidee.fdfalcon.falcon.FalconAlarmService;
import com.feidee.fdfalcon.falcon.FalconReportService;
import com.uhb.base.controller.BaseController;
import com.uhb.base.util.CommonFunctionUtil;
import io.netty.util.internal.StringUtil;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.mail.internet.MimeUtility;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller("feidee_reporter_controller")
@RequestMapping("/")
public class DataReporterController extends BaseController {

    @Resource(name = "reporterService")
    private DataReporterService reporterService;
    @Resource(name = "funnelAnalyseService")
    private IFunnelAnalyseServices funnelAnalyseService;
    @Resource(name = "realTimeReportService")
    private IRealTimeReportServices realTimeReportService;

    @RequestMapping(value = "reporter")
    public ModelAndView query(@Valid @ModelAttribute ReportParam sp, BindingResult bingResult) throws Exception {
        // 判断秘钥是否正确，不正确报错 "Key或Apt有误"
        if (!checkAuth(sp.getApt(), sp.getKey(), Constant.SCRIT))
            return this.getJsonViewFail(-5).addObject(Constant.AUTH_INFO, Constant.APT_KEY_ERROR);

        int resCode = validateParams(sp);
        if (0 != resCode) {
            String errMsg = "";
            switch (resCode) {
                case 1:
                    errMsg = "请求参数错误:报表kpi为空.";
                    break;
                case 2:
                    errMsg = "请求参数非法:测试环境不允许全量执行报表.";
                    break;
                default:
                    errMsg = "未知错误.";
                    break;
            }
            return this.getJsonViewFail(-2).addObject(Constant.RETURE_RSLT, errMsg).addObject(Constant.COST_TIME, "0");
        }

        long start = System.currentTimeMillis(); // 获取当前时间f
        int res = reporterService.execute(sp);
        long cost = System.currentTimeMillis() - start; // 执行总时间
        if (res != 0) // res为空返回执行耗时
            return this.getJsonViewFail(-1).addObject(Constant.COST_TIME, cost + Constant.SM);
        return this.getJsonViewSuccess().addObject(Constant.RETURE_RSLT, res).addObject(Constant.COST_TIME,
                cost + Constant.SM);
    }

    /**
     * 参数检查
     *
     * @param sp
     * @return
     */
    private int validateParams(ReportParam sp) {

        String kpi = sp.getKpi();
        if (!ToolUtils.isNotNull(kpi)) {
            logger.info("报表执行 kpi为空，拒绝执行!");
            return 1;
        }
        if ("all".equalsIgnoreCase(kpi) && "test".equalsIgnoreCase(Constant.ENV)) {
            logger.info("测试环境不允许执行全部报表!");
            return 2;
        }

        return 0;
    }

    @RequestMapping(value = "auth-key")
    public ModelAndView createKey(@Valid @ModelAttribute AuthKeyParam sp, BindingResult bingResult)
            throws DataReporterServiceException {
        // 返回大写的加密密钥，用DES加密不安全
        return this.getJsonViewSuccess().addObject("auth key:",
                CommonFunctionUtil.createAuthkey(sp.getApt(), Constant.SCRIT));
    }

    @RequestMapping(value = "test-key")
    public ModelAndView testKey(@Valid @ModelAttribute AuthKeyParam ap, BindingResult bingResult)
            throws DataReporterServiceException {
        // 验证密钥是否正确
        return this.getJsonViewSuccess().addObject("Check auth key:",
                checkAuth(ap.getApt(), ap.getKey(), Constant.SCRIT));
    }

    @RequestMapping(value = "test-db")
    public ModelAndView testDB(@ModelAttribute String ap, BindingResult bingResult)
            throws DataReporterServiceException, SQLException, DataDaoException {
        // 连接mysql数据库
        Map<String, String> dbInfo = new HashMap<String, String>();
        dbInfo.put(Constant.MYSQL_URL,
                "jdbc:mysql://192.168.241.171:3306/data_report?useUnicode=true&amp;characterEncoding=utf8&amp;rewriteBatchedStatements=true");
        dbInfo.put(Constant.MYSQL_USER, "PT_reportsystem");
        dbInfo.put(Constant.MYSQL_PASSWORD, "6cc783d6f8cHcfc_5d67de5556db");
        dbInfo.put(Constant.MYSQL_JAVA_DRIVER_CLASS, "com.mysql.jdbc.Driver");
        Connection mysqlcon = null;
        mysqlcon = JdbcManager.getConnection(dbInfo);
        DatabaseMetaData mData = mysqlcon.getMetaData();
        return this.getJsonViewSuccess().addObject("test mysql conncention:", mData.getSchemaTerm());
    }

    /**
     * 自定义报表
     *
     * @param request
     * @param data
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "customreport")
    public void customReport(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        FalconReportService.metricIncr("data.report.customreport");
        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");
        logger.info("自定义报表参数: " + data);
        logger.info("自定义报表头信息 Authorization: " + request.getHeader("Authorization") + " ,Date: "
                + request.getHeader("Date"));

        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<CustomReportModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), CustomReportModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("自定义报表鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "自定义报表鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
        } else {
            CustomReportModel customReportModel = verifyResult.getData();
            // 校验数据源依赖依赖
            boolean isReady = reporterService.verifyDataResourcesDependency(customReportModel);
            if (isReady) {
                // 自定义报表
                reporterService.customReportOpr(customReportModel);
                // reporterService.customReportOpr(data);
                resultStr = getResultStr("0", request.getRequestURI(), "自定义报表请求提交成功");
            } else {
                resultStr = getResultStr("0", request.getRequestURI(), "自定义报表请求提交成功,依赖失败拒绝运行");
                response.getWriter().write(resultStr);
                return;
            }
        }
        response.getWriter().write(resultStr);
    }

    /**
     * 发布自定义报表
     *
     * @param data
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "crpulish")
    public void crPulish(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        FalconReportService.metricIncr("data.report.crpublish");
        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");
        logger.info("发布自定义报表参数: " + data);

        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<CustomReportModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), CustomReportModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "发布自定义报表鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
            logger.info("发布自定义报表 鉴权失败,失败原因: " + verifyResult.getErrMsg());
        } else if (ToolUtils.getNowHourAndMinute()
                .compareTo(CustomConfiguration.getString("custom.allow.publish.time", "22:30")) > 0) {
            resultStr = getResultStr("-3", request.getRequestURI(),
                    "发布自定义报表失败(" + data + "), 失败原因: " + "超过允许发布时间");
            logger.info("发布自定义报表失败,失败原因: 超过允许发布时间");
        } else {
            // 发布自定义报表
            CustomReportModel crpm = verifyResult.getData();
            // CRPublishModel crpm = JSONObject.parseObject(data,CRPublishModel.class);
            logger.info("发布自定义报表解密参数: " + crpm);
            crpm.setEnable("0");
            // 根据前端传过来的中文优先级转换成具体的数字
            crpm.setPriority(Constant.CUSTOM_PRIORITY.get(crpm.getPriority()));
            // 前端提交废除执行周期，统一设置为每天十点执行
            crpm.setPeriod("D10");
            // 校验数据源依赖依赖
            boolean isReady = reporterService.verifyDataResourcesDependency(crpm);
            if (isReady) {
                String res = reporterService.crmPublishOpr(crpm);
                String[] resArray = res.split(Constant.ERR_MSG_SPLIT_FLAG, -1);
                resultStr = getResultStr(resArray[0], request.getRequestURI(), resArray[1]);
            } else {
                resultStr = getResultStr("3", request.getRequestURI(), "数据源校验不通过");
                logger.info("发布自定义报表 " + crpm.getId() + " => " + crpm.getApplysqlname() + " 返回给前端结果: " + resultStr);
                response.getWriter().write(resultStr);
                return;
            }
            logger.info("发布自定义报表 " + crpm.getId() + " => " + crpm.getApplysqlname() + " 返回给前端结果: " + resultStr);
        }
        response.getWriter().write(resultStr);
    }

    /**
     * 获取接口返回信息JSON串
     *
     * @param code
     * @param requestName
     * @param msg
     * @return
     */
    private String getResultStr(String code, String requestName, String msg) {
        ResponseModel responseModel = new ResponseModel();
        responseModel.setCode(code);
        responseModel.setRequestName(requestName);
        responseModel.setMsg(msg);

        return JSONObject.toJSONString(responseModel);
    }

    /**
     * 查询报表项目日志
     *
     * @param filename
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "readlog")
    public void readLog(@RequestParam String filename, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        String webRootPath = request.getSession().getServletContext().getRealPath("/");
        Character separatorChar = File.separatorChar;
        if (!ToolUtils.isNotNull(filename)) {
            filename = "info.log";
        }
        String logDir = webRootPath.split("webapps")[0] + "feideedatalogs" + separatorChar + filename;
        logger.info("获取日志文件名 :" + logDir);
        File file = new File(logDir);
        if (file.exists()) {
            if (response != null) {
                InputStream in = new FileInputStream(file);
                String fileName = file.getName();
                String agent = response.getHeader("USER-AGENT");
                if (null != agent && -1 != agent.indexOf("Mozilla")) {
                    String firefox = MimeUtility.encodeText(fileName, "UTF-8", "B");
                    response.setHeader("Content-Disposition", "attachment; filename=" + firefox);
                } else {
                    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
                }
                ServletOutputStream out = response.getOutputStream();
                byte[] buffered = new byte[1024];
                int length = 0;
                while ((length = in.read(buffered)) != -1) {
                    out.write(buffered, 0, length);
                }
                out.write(buffered);
                out.flush();
                out.close();
                in.close();
            }
            logger.info("获取文件成功!");
        } else {
            response.getWriter().write("没有该文件:" + logDir);
        }
    }

    /**
     * 停止执行某个报表的历史SQL
     *
     * @param data
     * @return
     */
    @RequestMapping(value = "stoptask")
    public void stopTask(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");
        logger.info("停止自定义报表运行参数: " + data);

        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<StopRunReportModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), StopRunReportModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("停止自定义报表运行鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "停止自定义报表运行鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
        } else {
            StopRunReportModel stopRunReportKey = verifyResult.getData();
            String reportKey = stopRunReportKey.getReportKey();
            logger.info("停止报表执行信号: " + reportKey);
            //加入停止信号
            RunFlagController.stopReportExecute(reportKey);
            logger.info("当前正在运行的报表:" + RunFlagController.getRunFlagCacheStr());
            resultStr = getResultStr("0", request.getRequestURI(), "停止自定义报表运行请求提交成功");
        }

        response.getWriter().write(resultStr);
    }

    /**
     * 创建结果表
     *
     * @param request
     * @param data
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "buildrestbl")
    public void createResultTbl(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");
        logger.info("创建结果表接口请求参数: " + data);

        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<BuildResultTblModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), BuildResultTblModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("创建结果表接口鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "创建结果表接口鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
        } else {
            BuildResultTblModel brtm = verifyResult.getData();
            logger.info("创建结果表接口解密参数: " + JSON.toJSONString(brtm));

            //参数检查
            if (null != brtm) {
                if ((!ToolUtils.isNotNull(brtm.getApplysqlname())) || (null == brtm.getMysqlColumn()) ||
                        (!ToolUtils.isNotNull(brtm.getApplyname()))) {
                    resultStr = getResultStr("-3", request.getRequestURI(), "请求参数有误");
                } else {
                    String resStr = reporterService.buildResultTbl(brtm);
                    String[] resArray = resStr.split(Constant.ERR_MSG_SPLIT_FLAG, -1);
                    resultStr = getResultStr(resArray[0], request.getRequestURI(), resArray[1]);
                }
            } else {
                resultStr = getResultStr("-3", request.getRequestURI(), "请求参数有误");
            }

        }

        logger.info("创建结果表接口返回给前端结果: " + resultStr);
        response.getWriter().write(resultStr);
    }

    /**
     * 下线报表接口
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "offlinereport")
    public void offlineReport(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");

        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<String> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), String.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("下线报表接口鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "下线报表接口鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
        } else {
            String reportKey = verifyResult.getData();
            String resStr = reporterService.offlineReportKey(reportKey);
            String[] resArray = resStr.split(Constant.ERR_MSG_SPLIT_FLAG, -1);
            resultStr = getResultStr(resArray[0], request.getRequestURI(), resArray[1]);
            logger.info("下线报表 " + reportKey + " 返回给前端结果: " + resultStr);
        }

        response.getWriter().write(resultStr);

    }

    /**
     * 停止执行某个报表的历史SQL
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "reportruninfo")
    public void reportruninfo(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        logger.info("获取报表执行线程状态信息...");
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write(ToolUtils.getHostAddress() + ":" + ThreadPoolUtil.dataReportRunInfoCache());
    }



    /**
     * 实时报表查询接口
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "realTimeReport")
    public void realTimeReport(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        RealTimeParam realTimeParam;
        String request_id = ToolUtils.getUuid();
        String resultStr;
        response.setContentType("text/html;charset=UTF-8");
        long startTime = System.currentTimeMillis();
        // api鉴权
        AuthorizationModel<RealTimeParam> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), RealTimeParam.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("实时报表鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getRealTimeResultStr(request_id, null, "-2", "鉴权失败");
        } else {
            realTimeParam = verifyResult.getData();

            logger.info("实时报表查询ID " + request_id + " 解密参数为: " + realTimeParam.toString());
            Map<String, String> searchSql = realTimeReportService.getSearchSql(realTimeParam);
            logger.info("实时报表查询ID " + request_id + " 查询SQL为: " + searchSql);
            if (searchSql == null) {
                resultStr = getRealTimeResultStr(request_id, null, "-3", "拼接SQL失败");
                response.getWriter().write(resultStr);
                return;
            }
            List<JSONObject> realTimeResults = realTimeReportService.runSql(realTimeParam.getViews(), searchSql);
            if (realTimeResults == null) {
                logger.info("实时报表查询ID " + request_id + " 查询失败");
                resultStr = getRealTimeResultStr(request_id, null, "-1", "查询失败");
            } else {
                logger.info("实时报表查询ID " + request_id + " 查询成功");
                resultStr = getRealTimeResultStr(request_id, realTimeResults, "0", "SUCCESS");
            }
        }
        String logStr = resultStr.substring(0, resultStr.length() > 1000 ? 1000 : resultStr.length());
        logger.info("实时报表查询ID " + request_id + " 返回结果为：" + logStr);
        response.getWriter().write(resultStr);
        long endTime = System.currentTimeMillis();
        logger.info("实时报表查询ID " + request_id + " 查询耗时：" + (endTime - startTime) + "ms");
    }

    /**
     * 实时报表聚合计算接口
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "realTimeReportCal")
    public void realTimeReportCal(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        RealTimeParam realTimeParam;
        String request_id = ToolUtils.getUuid();
        String resultStr;
        response.setContentType("text/html;charset=UTF-8");
        long startTime = System.currentTimeMillis();
        // api鉴权
        AuthorizationModel<RealTimeParam> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), RealTimeParam.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("实时报表聚合计算鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getRealTimeResultStr(request_id, null, "-2", "鉴权失败");
        } else {
            realTimeParam = verifyResult.getData();
            logger.info("实时报表聚合计算查询ID " + request_id + " 解密参数为: " + realTimeParam.toString());
            Map<String, String> searchSql = realTimeReportService.getSearchSql(realTimeParam);
            logger.info("实时报表聚合计算查询ID " + request_id + " 查询SQL为: " + searchSql);
            if (searchSql == null) {
                resultStr = getRealTimeResultStr(request_id, null, "-3", "拼接SQL失败");
                response.getWriter().write(resultStr);
                return;
            }
            JSONObject realTimeCalResults = realTimeReportService.aggCal(realTimeParam, searchSql);
            if (realTimeCalResults == null) {
                logger.info("实时报表聚合计算查询ID " + request_id + " 查询失败");
                resultStr = getRealTimeResultStr(request_id, null, "-1", "查询失败");
            } else {
                logger.info("实时报表聚合计算查询ID " + request_id + " 查询成功");
                resultStr = getRealTimeResultStr(request_id, realTimeCalResults, "0", "SUCCESS");
            }
        }
        String logStr = resultStr.substring(0, resultStr.length() > 1000 ? 1000 : resultStr.length());
        logger.info("实时报表聚合计算查询ID " + request_id + " 返回结果为：" + logStr);
        response.getWriter().write(resultStr);
        long endTime = System.currentTimeMillis();
        logger.info("实时报表聚合计算查询ID " + request_id + " 查询耗时：" + (endTime - startTime) + "ms");
    }


    /**
     * 实时报表查询配置接口
     *
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "getRealTimeConfig")
    public void getRealTimeConfig(HttpServletResponse response)
            throws Exception {
        response.setContentType("text/html;charset=UTF-8");
        String config = realTimeReportService.getConfig();
        logger.info("实时报表获取到配置信息: " + config);
        response.getWriter().write(config);
    }

    /**
     * 实时报表配置业务线及视图配置接口
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "realTimeConfig")
    public void realTimeConfig(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        RealTimeConfigModel realTimeConfigModel;
        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");
        // api鉴权
        AuthorizationModel<RealTimeConfigModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), RealTimeConfigModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("实时报表配置鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getRealTimeConfigResultStr("-1", "鉴权失败");
        } else {
            realTimeConfigModel = verifyResult.getData();
            logger.info("实时报表配置解密参数为: " + realTimeConfigModel.toString());

            String code = realTimeReportService.setConfig(realTimeConfigModel);

            if ("0".equals(code)) {
                resultStr = getRealTimeConfigResultStr("0", "配置设置成功");
            } else {
                resultStr = getRealTimeConfigResultStr(code, "配置设置失败");
            }
        }
        logger.info("实时报表配置返回结果: " + resultStr);
        response.getWriter().write(resultStr);
    }

    private String getRealTimeResultStr(String request_id, Object result, String code, String msg) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("request_id", request_id);
        jsonObject.put("result", result);
        jsonObject.put("code", code);
        jsonObject.put("msg", msg);
        return jsonObject.toJSONString();
    }

    private String getRealTimeConfigResultStr(String code, String msg) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", code);
        jsonObject.put("msg", msg);
        return jsonObject.toJSONString();
    }


    /**
     * 更新报表配置
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     * @author SJ
     */
    @RequestMapping(value = "updateReportConfig")
    public void updateReportConfig(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        String resultStr;
        response.setContentType("text/html;charset=UTF-8");
        ReportConfigParam reportConfigParam;
        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<ReportConfigParam> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), ReportConfigParam.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("更新报表配置接口鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "更新报表配置接口鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
        } else {
            reportConfigParam = verifyResult.getData();
            resultStr = reporterService.updateReportConfig(reportConfigParam);
        }

        response.getWriter().write(resultStr);
    }

    /**
     * 报表源数据状态记录接口
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "metadataStatus")
    public void metadataStatus(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        FalconReportService.metricIncr("data.report.metadataStatus");
        String status;
        String result;
        JSONObject returnResult = new JSONObject();
        String requestId = ToolUtils.getUuid();
        response.setContentType("text/html;charset=UTF-8");
        DataResourcesModel dataResourcesModel;
        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<DataResourcesModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), DataResourcesModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("请求ID [" + requestId + "] 更新报表数据源状态鉴权失败,失败原因: " + verifyResult.getErrMsg());
            result = "鉴权失败";
            status = "-2";
        } else {
            dataResourcesModel = verifyResult.getData();
            logger.info("请求ID [" + requestId + "] 数据源更新状态请求参数: " + dataResourcesModel);
            status = reporterService.updateDataResources(dataResourcesModel);
            if (status.equals("0")) {
                result = "数据源更新状态成功";
                // 重新运行依赖该数据源且之前运行失败或等待超时的报表
                reporterService.rerunDataResourcesReport(dataResourcesModel);
            } else if (status.equals("2")) {
                result = "数据源更新时间非当天";
            } else {
                result = "数据源更新状态失败";
            }
        }
        returnResult.put("id", requestId);
        returnResult.put("'status'", status);
        returnResult.put("msg", result);
        response.getWriter().write(returnResult.toJSONString());
    }

    /**
     * 前端手动运行报表接口
     *
     * @param data
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "runReport")
    public void runReport(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        String reportKey;
        String msg = "success";
        String requestId = ToolUtils.getUuid();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", requestId);
        response.setContentType("text/html;charset=UTF-8");
        // api鉴权
        AuthorizationModel<DataMonitorModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), DataMonitorModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            msg = "鉴权失败,失败原因: " + verifyResult.getErrMsg();
            jsonObject.put("status", "-1");
            logger.info("请求ID [" + requestId + "] " + msg);
        } else {
            reportKey = verifyResult.getData().getReportKey();
            logger.info("前端运行报表参数为: " + reportKey);
            if (!ToolUtils.isNotNull(reportKey)) {
                logger.info("请求ID [" + requestId + "] 报表执行 kpi为空，拒绝执行!");
                msg = "报表名不允许为空";
                jsonObject.put("status", "-2");
            } else if ("all".equalsIgnoreCase(reportKey)) {
                logger.info("请求ID [" + requestId + "] 前端手动运行拒绝执行全量报表!");
                msg = "报表名不允许为all";
                jsonObject.put("status", "-2");
            }
            if ("success".equals(msg)) {
                ReportParam sp = new ReportParam();
                sp.setKpi(reportKey);
                reporterService.execute(sp);
                logger.info("请求ID [" + requestId + "] 报表 " + reportKey + " 成功提交运行!");
                jsonObject.put("status", "0");
            }
        }
        jsonObject.put("msg", msg);
        response.getWriter().write(jsonObject.toJSONString());
    }

    /**
     * @author CHQ
     * @date 2019-11-4
     * @description 现将报表依赖分为上下游，上下游各自只有一层
     */
    @RequestMapping(value = "getDependency")
    public void getDependency(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        DependencyModel result = new DependencyModel();
        String reportKey = null;
        response.setContentType("text/html;charset=UTF-8");
        // api鉴权
        AuthorizationModel<DataMonitorModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), DataMonitorModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("获取报表依赖鉴权失败,失败原因: " + verifyResult.getErrMsg());
            result.setStatus("-1");
            result.setMsg("鉴权失败,失败原因: " + verifyResult.getErrMsg());
        } else {
            reportKey = verifyResult.getData().getReportKey();
            result.setReport_key(reportKey);
            logger.info("前端查询报表依赖参数为: " + reportKey);
            reporterService.getDataResourcesAndReportDependency(reportKey, result);
        }
        String toJSONString = JSONObject.toJSONString(result);
        logger.info("前端查询报表：" + reportKey + " 依赖返回结果为: " + toJSONString);
        response.getWriter().write(toJSONString);
    }

   /*
    * @Author: chq
    * @desc: 现前端监控页面依赖表候选框中只针对依赖的数据源表和上游依赖报表进行处理
    * @date: 2020/9/8 11:11
    */
    @RequestMapping(value = "getResourcesReport")
    public void getResourcesReport(@RequestParam String data, HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        DependencyResourcesModel dependencyResourcesModel = new DependencyResourcesModel();
        List<String> resourcesDependencyReport = null;
        String reportKey = null;
        response.setContentType("text/html;charset=UTF-8");
        // api鉴权
        AuthorizationModel<DataMonitorModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), DataMonitorModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("获取依赖指定源表或报表的报表鉴权失败,失败原因: " + verifyResult.getErrMsg());
            dependencyResourcesModel.setStatus("-1");
            dependencyResourcesModel.setMsg("鉴权失败,失败原因: " + verifyResult.getErrMsg());
        } else {
            reportKey = verifyResult.getData().getReportKey();
            logger.info("获取依赖指定源表或报表的报表参数为: " + reportKey);
            if (!ToolUtils.isNotNull(reportKey)) {
                logger.info("获取依赖指定源表或报表的报表参数不允许为空！");
                dependencyResourcesModel.setStatus("-2");
                dependencyResourcesModel.setMsg("获取依赖指定源表或报表的报表参数不允许为空");
            } else {
                if(reportKey.contains(".")){
                    //获取上游依赖的数据源表的报表
                    resourcesDependencyReport = reporterService.getResourcesDependencyReport(reportKey);
                }else {
                   //获取上游依赖的Mysql结果表的报表
                resourcesDependencyReport = reporterService.getReportOfDownDependency(reportKey);
                }
                if (resourcesDependencyReport == null) {
                    dependencyResourcesModel.setStatus("-3");
                    dependencyResourcesModel.setMsg("获取依赖报表异常");
                } else {
                    dependencyResourcesModel.setStatus("0");
                    dependencyResourcesModel.setMsg("success");
                }
            }
        }
        dependencyResourcesModel.setReport_keys(resourcesDependencyReport);
        String toJSONString = JSONObject.toJSONString(dependencyResourcesModel);
        logger.info("获取依赖指定源表或报表：" + reportKey + " 依赖的报表返回结果为: " + toJSONString);
        response.getWriter().write(toJSONString);
    }

    /**
     * @author CHQ
     * @description 修复自定义报表发布问题
     */
    @RequestMapping(value = "customReportPublishFix")
    public void customReportPublishFix(HttpServletResponse response) throws Exception {
        reporterService.fix();
        response.getWriter().write("{\"code\":0,\"msg\":\"发版任务快速失败完成!\"}");
    }

    /**
     * 更新报表执行周期
     * @param data
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "updatePerformancePeriod")
    public void updatePerformancePeriod(@RequestParam String data, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String resultStr = null;
        response.setContentType("text/html;charset=UTF-8");
        logger.info("更新报表执行周期参数: " + data);
        logger.info("更新报表执行周期头信息 Authorization: " + request.getHeader("Authorization") + " ,Date: "
                + request.getHeader("Date"));

        // api鉴权(鉴权失败,前端传递参数错误导致JSON转对象失败都会在此处进行处理)
        AuthorizationModel<CustomReportModel> verifyResult = AuthorizationVerify.verify(request, data,
                CustomConfiguration.getInt("request.interval", 15), CustomReportModel.class);
        int authCode = verifyResult.getCode();
        if (authCode != 0) {
            logger.info("更新报表执行周期鉴权失败,失败原因: " + verifyResult.getErrMsg());
            resultStr = getResultStr("-2", request.getRequestURI(),
                    "更新报表执行周期鉴权失败(" + data + "), 失败原因: " + verifyResult.getErrMsg());
        } else {
            CustomReportModel customReportModel = verifyResult.getData();
            if (!ToolUtils.isNotNull(customReportModel.getApplysqlname()) ||
                    !ToolUtils.isNotNull(customReportModel.getPeriod())){
                logger.info("更新报表执行周期参数异常");
                resultStr = getResultStr("-1", request.getRequestURI(), "更新报表执行周期参数异常");
            }else{
                // 校验数据源依赖依赖
                Boolean flag = reporterService.updatePeriod(customReportModel);
                if (flag) {
                    resultStr = getResultStr("0", request.getRequestURI(), "更新报表执行周期成功");
                } else {
                    resultStr = getResultStr("-3", request.getRequestURI(), "更新报表执行周期失败");
                }
            }
        }
        response.getWriter().write(resultStr);
    }

}